package com.swt.gap.service.impl;

import com.alibaba.fastjson.JSON;
import com.swt.gap.dao.ModelClassMapper;
import com.swt.gap.dao.ModelMapper;
import com.swt.gap.model.entity.ModelClass;
import com.swt.gap.model.entity.ModelWithBLOBs;
import com.swt.gap.model.graphmodel.*;
import com.swt.gap.model.vo.ModelByClassVO;
import com.swt.gap.model.vo.ModelVO;
import com.swt.gap.service.ModelService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ModelServiceImpl implements ModelService {

    private final ModelMapper modelMapper;
    private final ModelClassMapper modelClassMapper;

    public ModelServiceImpl(ModelMapper modelMapper, ModelClassMapper modelClassMapper) {
        this.modelMapper = modelMapper;
        this.modelClassMapper = modelClassMapper;
    }

    @Override
    public Integer saveModel(ModelVO model) {
        ModelWithBLOBs modelWithBLOBs = transferData(model);
        int retValue = modelMapper.insertSelective(modelWithBLOBs);
        model.setModelId(modelWithBLOBs.getModelId());
        return retValue;
    }

    @Override
    public ModelVO getModelById(Integer modelId) {
        ModelVO retValue = new ModelVO();
        ModelWithBLOBs modelWithBLOBs = modelMapper.selectByPrimaryKey(modelId);
        if (null == modelWithBLOBs) {
            return null;
        }
        BeanUtils.copyProperties(modelWithBLOBs, retValue);
        retValue.setGraphModels(JSON.parseArray(modelWithBLOBs.getGraphModel(), GraphTemplate.class));
        retValue.setEventModels(JSON.parseArray(modelWithBLOBs.getEventModel(), EventGraphModel.class));
        return retValue;
    }

    @Override
    public Integer updateModel(ModelVO model) {
        return modelMapper.updateByPrimaryKeySelective(transferData(model));
    }

    @Override
    public Set<String> getMatchFieldsFromTemplate(List<GraphTemplate> listGraphTemplates) {
        Set<String> matchFields = new HashSet<>();
        listGraphTemplates.forEach(graphTemplate -> {
            Optional.ofNullable(graphTemplate.getEntityTemplateOne().getPrimaryKeyPropertyKey()).ifPresent(matchFields::add);
//            Optional.ofNullable(graphTemplate.getEntityTemplateOne().getDisplayPropertyKey()).ifPresent(matchFields::add);
            graphTemplate.getEntityTemplateOne().getProperties().forEach(property -> matchFields.add(property.getFieldOrigin()));

            Optional.ofNullable(graphTemplate.getEntityTemplateTwo().getPrimaryKeyPropertyKey()).ifPresent(matchFields::add);
//            Optional.ofNullable(graphTemplate.getEntityTemplateTwo().getDisplayPropertyKey()).ifPresent(matchFields::add);
            graphTemplate.getEntityTemplateTwo().getProperties().forEach(property -> matchFields.add(property.getFieldOrigin()));

            Optional.ofNullable(graphTemplate.getRelationshipTemplate().getTypeFiled()).ifPresent(matchFields::add);
            Optional.ofNullable(graphTemplate.getRelationshipTemplate().getDisplayPropertyKey()).ifPresent(matchFields::add);
            Optional.ofNullable(graphTemplate.getRelationshipTemplate().getTimeProperty())
                    .map(TimeProperty::getTimeField)
                    .ifPresent(matchFields::add);
            Optional.ofNullable(graphTemplate.getRelationshipTemplate().getDirectionConfig())
                    .map(DirectionConfig::getDirectionField)
                    .map(DirectionField::getField)
                    .ifPresent(matchFields::add);
            graphTemplate.getRelationshipTemplate().getProperties().forEach(property -> matchFields.add(property.getFieldOrigin()));
        });
        matchFields.remove("");
        return matchFields;
    }

    @Override
    public List<ModelByClassVO> listModel() {
        List<ModelByClassVO> retValue = new ArrayList<>();
        List<ModelClass> modelClasses = modelClassMapper.selectAll();
        modelClasses.forEach(modelClass -> {
            ModelByClassVO modelByClassVO = new ModelByClassVO();
            modelByClassVO.setModelClassId(modelClass.getModelClassId());
            modelByClassVO.setClassName(modelClass.getClassName());
            modelByClassVO.setModels(modelMapper.selectByClassId(modelClass.getModelClassId()));
            retValue.add(modelByClassVO);
        });
        return retValue;
    }


    private ModelWithBLOBs transferData(ModelVO record) {
        ModelWithBLOBs fileTemplateWithBLOBs = new ModelWithBLOBs();
        BeanUtils.copyProperties(record, fileTemplateWithBLOBs);

        List<GraphTemplate> graphTemplates = record.getGraphModels();
        Optional.ofNullable(graphTemplates).ifPresent(listGraphTemplates -> {

            Set<String> matchFields = getMatchFieldsFromTemplate(listGraphTemplates);
            fileTemplateWithBLOBs.setGraphModel(JSON.toJSONString(graphTemplates));
            fileTemplateWithBLOBs.setMatchField(StringUtils.join(matchFields
                            .stream()
                            .filter(field -> !StringUtils.isEmpty(field))
                            .collect(Collectors.toSet()),","));


            List<EventGraphModel> eventGraphModelList = record.getEventModels();
            Optional.ofNullable(eventGraphModelList).ifPresent(eventGraph -> {
                fileTemplateWithBLOBs.setEventModel(JSON.toJSONString(eventGraph));
            });
        });
        return fileTemplateWithBLOBs;
    }

}
